POST /short-link/internal - 内部短链接创建接口
接口功能说明
该接口用于内部服务间通信,将任意长URL转换为短链接(s.pear.us 域名)。主要用于字符限制场景,如短信模板、邮件模板、营销推广链接等。
[!info] 与
/short-link/create的区别 | 特性 |/short-link/internal|/short-link/create| |------|------------------------|----------------------| | 认证方式 | JWT Token (BUSINESS_PARTNER) | AdminGuard (管理员权限) | | 使用场景 | 服务间调用、业务系统集成 | 管理后台手动创建 | | 权限要求 | 需要 JWT Token | 需要管理员权限 |
请求地址 & 请求方式
POST /short-link/internal
环境示例:
- Release:
https://release.katana-api.1m.app/short-link/internal - Development:
http://localhost:4000/short-link/internal
请求头 (Headers)
| Header | 必填 | 类型 | 说明 |
|---|---|---|---|
Authorization |
✅ | string |
JWT Token,格式:Bearer <token> |
Content-Type |
✅ | string |
必须为 application/json |
from |
❌ | string |
来源标识,如 client |
x-track-id |
❌ | string |
追踪ID,用于请求链路追踪 |
请求参数 (Body)
请求体结构
| 字段 | 必填 | 类型 | 说明 | 示例 |
|---|---|---|---|---|
originalUrl |
✅ | string |
需要缩短的原始URL(完整URL) | https://release.pear.us/neo/post/000011?aff=ehf843 |
ttlDays |
❌ | number |
短链接有效期(天数),不传则永久有效 | 30 |
TypeScript 类型定义
export interface CreateGenericShortLinkRequest {
originalUrl: string; // 必填:原始URL
ttlDays?: number; // 可选:有效期(天数)
}
请求示例
{
"originalUrl": "https://release.pear.us/neo/post/000011?aff=ehf843"
}
带有效期的请求:
{
"originalUrl": "https://release.pear.us/neo/post/000011?aff=ehf843",
"ttlDays": 30
}
响应结构 & 字段说明
成功响应
HTTP Status Code: 200 OK
export interface CreateShortLinkResponse {
shortUrl: string; // 短链接完整地址
code: string; // 短链接码(短链接的最后部分)
originalUrl: string; // 原始URL
createdAt: string; // 创建时间(ISO 8601格式)
expiresAt?: string; // 过期时间(ISO 8601格式,如有设置ttlDays)
}
| 字段 | 类型 | 说明 |
|---|---|---|
shortUrl |
string |
短链接完整地址,格式:https://s.pear.us/{code} |
code |
string |
短链接码,用于手动构建短链接 |
originalUrl |
string |
原始URL(与请求参数一致) |
createdAt |
string |
短链接创建时间,ISO 8601格式 |
expiresAt |
string |
过期时间,仅在设置 ttlDays 时返回 |
成功示例
Request:
curl -X POST 'https://release.katana-api.1m.app/short-link/internal' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' \
-H 'Content-Type: application/json' \
-d '{
"originalUrl": "https://release.pear.us/neo/post/000011?aff=ehf843"
}'
Response:
{
"shortUrl": "https://s.pear.us/abc123xyz",
"code": "abc123xyz",
"originalUrl": "https://release.pear.us/neo/post/000011?aff=ehf843",
"createdAt": "2026-02-27T09:30:00.000Z"
}
带有效期的响应示例:
{
"shortUrl": "https://s.pear.us/abc123xyz",
"code": "abc123xyz",
"originalUrl": "https://release.pear.us/neo/post/000011?aff=ehf843",
"createdAt": "2026-02-27T09:30:00.000Z",
"expiresAt": "2026-03-29T09:30:00.000Z"
}
异常场景 & 错误响应
错误响应格式
export interface ShortLinkApiResponse<T = unknown> {
success: boolean; // false 表示失败
error?: string; // 错误信息
statusCode: number; // HTTP状态码
}
错误场景列表
| HTTP状态码 | 错误场景 | 错误信息示例 |
|---|---|---|
401 |
JWT Token 无效或过期 | Unauthorized |
400 |
请求参数缺失 | originalUrl is required |
500 |
短链接服务配置错误 | SHORT_LINK_API_URL environment variable is required |
500 |
短链接API调用失败 | Failed to create short link: ... |
500 |
请求超时 | timeout of 10000ms exceeded |
错误示例
1. 认证失败 (401)
{
"statusCode": 401,
"message": "Unauthorized"
}
2. 环境变量未配置 (500)
{
"statusCode": 500,
"message": "SHORT_LINK_API_URL environment variable is required"
}
3. 短链接API错误 (500)
{
"statusCode": 500,
"message": "Failed to create short link: Invalid URL format"
}
业务逻辑详解
处理流程
sequenceDiagram
participant Client as 客户端
participant Controller as ShortLinkController
participant Service as ShortLinkService
participant ExternalAPI as 短链接外部API
Client->>Controller: POST /short-link/internal
Note over Client,Controller: Authorization: Bearer <JWT>
Controller->>Service: createShortLink(originalUrl, ttlDays)
Note over Service: 验证环境变量
Service->>ExternalAPI: POST /create
Note over Service,ExternalAPI: 10秒超时
ExternalAPI-->>Service: CreateShortLinkResponse
Note over Service: 验证响应成功
Service-->>Controller: CreateShortLinkResponse
Controller-->>Client: 200 OK + 短链接数据
环境依赖
| 环境变量 | 必填 | 说明 |
|---|---|---|
SHORT_LINK_API_URL |
✅ | 短链接服务API地址 |
SHORT_LINK_API_KEY |
✅ | 短链接服务API密钥 |
超时设置
- API调用超时:
10000ms(10秒) - 超时后抛出异常并返回错误响应
认证逻辑
该接口受全局 JwtAuthGuard 保护:
- 请求头必须包含有效的 JWT Token
- Token中必须包含有效的用户信息
- Token过期后返回
401 Unauthorized
数据库操作说明
[!important] 数据库操作隔离 该接口在 katana-server 中不涉及任何数据库操作,所有数据存储由独立的短链接服务负责。
katana-server 侧:无数据库操作
客户端 → ShortLinkController → ShortLinkService → 外部短链接API
↓
(s.pear.us 服务数据库)
本接口在 katana-server 中仅作为 HTTP 代理:
// short-link.service.ts 核心逻辑
async createShortLink(url: string, ttlDays?: number) {
// 1. 从配置读取环境变量(无数据库查询)
const apiUrl = this.configService.get<string>('SHORT_LINK_API_URL');
const apiKey = this.configService.get<string>('SHORT_LINK_API_KEY');
// 2. 直接调用外部API(无数据库写入)
const response = await axios.post(`${apiUrl}/create`, request, {
headers: { Authorization: `Bearer ${apiKey}` },
timeout: 10000,
});
// 3. 返回外部API的响应
return response.data.data;
}
外部短链接服务:负责数据库操作
独立的短链接服务(s.pear.us)负责以下数据库操作:
| 操作 | 说明 | 数据表(推测) |
|---|---|---|
| 写入 | 存储短链接码 → 原始URL 的映射关系 | short_links |
| 读取 | 用户访问短链接时查询原始URL并重定向 | short_links |
| 清理 | 过期短链接的定期清理(如实现了TTL机制) | 定时任务 |
架构设计优势
graph LR
A[katana-server] -- HTTP代理 --> B[s.pear.us 短链接服务]
B -- 存储/查询 --> C[(短链接数据库)]
A -.无直接操作.-> C
style A fill:#e3f2fd
style B fill:#fff9c4
style C fill:#f3e5f5
[!tip] 服务分离设计的优势
- 解耦: 短链接逻辑独立,不影响主业务数据库
- 复用: 其他服务可直接调用短链接服务,无需重复实现
- 维护: 短链接算法升级/扩容只需修改外部服务
- 性能: 短链接高并发访问不影响主业务系统
- 独立部署: 可根据短链接访问量独立扩缩容
注意事项
[!warning] URL 格式要求
originalUrl必须是完整的、有效的 URL- 必须包含协议(
http://或https://)- URL中的特殊字符无需手动编码,服务会自动处理
[!warning] 短链接唯一性
- 同一个
originalUrl多次调用可能生成不同的短链接- 如需复用已有短链接,请在调用端实现缓存逻辑
[!warning] 有效期计算
ttlDays参数表示从创建之日起的有效天数- 不传该参数则短链接永久有效
- 过期后短链接将无法访问
[!tip] 建议使用场景
- ✅ 短信营销链接
- ✅ 邮件模板中的商品链接
- ✅ 社交媒体推广链接
- ✅ 带追踪参数的联盟链接(如
?aff=xxx)- ✅ 二维码生成(短链接生成更简单的二维码)
[!danger] 安全注意
- 不要将敏感信息(如密码、Token)放在短链接中
- 短链接可被推算,不适合作为私密访问入口
- 建议为敏感内容设置较短的有效期
代码位置
| 文件 | 路径 |
|---|---|
| Controller | src/short-link/short-link.controller.ts:66-72 |
| Service | src/short-link/short-link.service.ts:26-75 |
| DTO | src/short-link/dto/short-link.dto.ts:6-9 |
相关接口
- [[POST /short-link/create]] - 管理员创建短链接
- [[POST /short-link/verification]] - 创建验证链接